package liuyang.bigeventserver.modules.security.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import liuyang.bigeventserver.common.Id;
import liuyang.bigeventserver.modules.security.entity.User;
import liuyang.bigeventserver.modules.security.mapper.UserMapper;
import liuyang.bigeventserver.modules.security.vo.SysUserDetails;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Collections;

/**
 * 认证过程只需要loadUserByUsername
 * 这个方法在UserDetailsService，也就是UserDetailsManager继承的接口中。
 * 其他方法看系统使用的情况酌情实现即可。
 *
 * 编码可以参考InMemoryUserDetailsManager
 *
 * 视频参考：
 * 认证：
 * https://www.bilibili.com/video/BV14b4y1A7Wz/?p=13&vd_source=8bd7b24b38e3e12c558d839b352b32f4
 * https://www.bilibili.com/video/BV14b4y1A7Wz/?p=14&spm_id_from=pageDriver&vd_source=8bd7b24b38e3e12c558d839b352b32f4
 * 添加用户：
 * https://www.bilibili.com/video/BV14b4y1A7Wz/?p=16&spm_id_from=pageDriver&vd_source=8bd7b24b38e3e12c558d839b352b32f4
 *
 * @author xconf
 * @since 2024/2/27
 *        2024/3/2  定制SysUserDetails，增加ID字段，方便放入上下文中传递。
 */
@Service
@AllArgsConstructor
@Slf4j
public class DBUserDetailsServie implements UserDetailsManager, UserDetailsPasswordService {

    private final UserMapper userMapper;
    private final PasswordEncoder passwordEncoder;

    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {
        // TODO
        return null;
    }

    @Override
    public void createUser(UserDetails user) {
        log.debug("user = {}", user);
        User entity = new User();
        entity.setId(Id.nextId());// snowflake
        entity.setUsername(user.getUsername());
        entity.setPassword(passwordEncoder.encode(user.getPassword()));
        // 后续考虑使用MyBatis-Plus的自动填充
        entity.setCreateTime(LocalDateTime.now());
        entity.setUpdateTime(LocalDateTime.now());
        userMapper.insert(entity);
    }

    @Override
    public void updateUser(UserDetails user) {
        // TODO
    }

    @Override
    public void deleteUser(String username) {
        // TODO
    }

    @Override
    public void changePassword(String oldPassword, String newPassword) {
        // TODO
    }

    @Override
    public boolean userExists(String username) {
        final LambdaQueryWrapper<User> userLambdaQueryWrapper = Wrappers.<User>lambdaQuery();
        userLambdaQueryWrapper.eq(User::getUsername, username);
        return userMapper.exists(userLambdaQueryWrapper);
    }

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        final LambdaQueryWrapper<User> userLambdaQueryWrapper = Wrappers.<User>lambdaQuery();
        userLambdaQueryWrapper.eq(User::getUsername, username);
        final User user = userMapper.selectOne(userLambdaQueryWrapper);
        // 参考InMemoryUserDetailsManager的写法。
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }
        // 20240302 为了把id塞进去，改成这个样子。
        // 上下文的Authentication的principal就会是这个对象，也就包含了id字段。
        return new SysUserDetails(user.getId()
                , user.getUsername()
                , user.getPassword()
                , true
                , true
                , true
                , true
                , Collections.emptyList());
        /*return new org.springframework.security.core.userdetails.User(
                user.getUsername()
                , user.getPassword()
                , true
                , true
                , true
                , true
                , Collections.emptyList());*/
        /*return new org.springframework.security.core.userdetails.User(user.getUsername()
                , user.getPassword()
                , user.isEnabled()
                , user.isAccountNonExpired()
                , user.isCredentialsNonExpired()
                , user.isAccountNonLocked()
                , user.getAuthorities());
        */
        // ok
        /*
        final UserDetails userDetails = org.springframework.security.core.userdetails.User
                .withUsername(user.getUsername())
                .password(user.getPassword())
                .build();
        return userDetails;
         */
    }
}
